package de.hsb.ai.util;

import game.Move;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ScotlandJadeGameLogger {
	
	public static final Logger logger = LoggerFactory.getLogger("sy.log");
	
	private static final String SEPARATOR	= " ";
	private static final String LOG_FORMAT	= "%d" + SEPARATOR + "%d" + SEPARATOR + "%d%n";
	
	private final File dir;
	private final String logFileNameFormat;
	private final Pattern regexp;
	
	private final boolean enabled;
	
	private BufferedWriter logFile;
	
	private FilenameFilter filter = new FilenameFilter() {
		
		@Override
		public boolean accept(File dir, String name) {
			return !name.startsWith(".") && regexp.matcher(name).matches() && new File(dir, name).length() > 0;
		}
		
	};
	
	public List<List<Entry>> read() {
		File[] files = dir.listFiles(filter);
		List<List<Entry>> res = new LinkedList<List<Entry>>();
		for (File file : files) {
			try {
				res.add(read(file));
			} catch (IOException e) {
				logger.error("reading " + file, e);
			}
		}
		return res;
	}
	
	private List<Entry> read(File file) throws IOException {
		List<Entry> entries = new LinkedList<ScotlandJadeGameLogger.Entry>();
		BufferedReader reader = new BufferedReader(new FileReader(file));
		String buffer;
		while ((buffer = reader.readLine()) != null) {
			StringTokenizer tokenizer = new StringTokenizer(buffer, SEPARATOR);
			entries.add(new Entry(
					Integer.parseInt(tokenizer.nextToken()),
					Integer.parseInt(tokenizer.nextToken()),
					Integer.parseInt(tokenizer.nextToken())));
			
		}
		return entries;
	}
	
	public ScotlandJadeGameLogger(String logFilePattern, boolean enabled) {
		dir = new File(logFilePattern).getParentFile();
		logFileNameFormat = new File(logFilePattern).getName();
		regexp = Pattern.compile(logFileNameFormat.replaceAll("%\\d*d", "(\\\\d+)"));
		this.enabled = enabled;
	}
	
	@Override
	public String toString() {
		return new StringBuilder(ScotlandJadeGameLogger.class.getSimpleName())
		.append(": ").append(dir).append(File.separatorChar).append(regexp).toString();
	}
	
	public void open() {
		if (!enabled) {
			logger.info("logger disabled");
			return;
		}
		
		if (logFile != null) {
			throw new IllegalStateException("log file still open!");
		}
		
		String[] files = dir.list(filter);
		Integer nextIndex = 0;
		if (files.length > 0) {
			Arrays.sort(files);
			Matcher matcher = regexp.matcher(files[files.length - 1]);
			if (matcher.find()) {
				String highestIndex = matcher.group(1);
				nextIndex = Integer.parseInt(highestIndex) + 1;
			}
		}
		File file = new File(dir, String.format(logFileNameFormat, nextIndex));
		logger.debug("opening new log file: " + file);
		
		try {
			logFile = new BufferedWriter(new FileWriter(file));
		} catch (IOException e) {
			logger.error("opening log file", e);
		}
	}
	
	public void logMove(int index, int from, Move move) {
		if (!enabled) 
			return;
		
		if (logFile == null)
			throw new IllegalStateException("log file has to be opened first");
		
		try {
			logFile.write(String.format(LOG_FORMAT, index, move.getNode(), move.getType()));
		} catch (IOException e) {
			logger.error("writing move log", e);
		}
	}
	
	public void close() {
		if (!enabled)
			return;
		
		if (logFile == null)
			throw new IllegalStateException("log file is not open");
		
		try {
			logFile.close();
			logFile = null;
		} catch (IOException e) {
			logger.error("closing logfile", e);
		}
	}
	
	public static class Entry {
		public Entry(int idx, int node, int transport) {
			this.idx = idx;
			this.node = node;
			this.transport = transport;
		}
		public final int idx;
		public final int node;
		public final int transport;
		
		@Override
		public String toString() {
			return "entry(" + idx + ", " + node + ", " + transport + ")";
		}
	}

}
